/* Hawk - An OSGI Based Test Framework
 *
 * Copyright (C) 2010 http://code.google.com/p/hawk-framework/
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */
package org.hawk.gui.windows;

import java.util.ResourceBundle;
import java.util.Set;

import org.hawk.gui.activator.OsgiContext;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceReference;
import org.hawk.core.interfaces.TestService;
import org.hawk.core.model.BundleGui;
import org.hawk.core.model.Step;

import com.vaadin.data.Property.ValueChangeEvent;
import com.vaadin.data.Property.ValueChangeListener;
import com.vaadin.ui.Button;
import com.vaadin.ui.ComboBox;
import com.vaadin.ui.Panel;
import com.vaadin.ui.TabSheet;
import com.vaadin.ui.TextField;
import com.vaadin.ui.VerticalLayout;
import com.vaadin.ui.Window;
import com.vaadin.ui.Button.ClickEvent;
import com.vaadin.ui.Button.ClickListener;

/**
 * This class creates the step configuration window 
 * 
 * @author Rodrigo Prestes Machado
 * @version November 15, 2009
 */
@SuppressWarnings("serial")
public class StepWindow extends Window {

	/** Localized System Messages */
	private ResourceBundle messages;
	
	/** This combo stores bundles from OSGI container  */
	private ComboBox bundlesCombo;

	/** Vaadin panel that stores bundle's user interface */
	private Panel bundlePanel;
	
	/** A Step object in the engine model  */
	private Step step;
	
	/** Enumeration of inputs */
	private enum parameters {VALUE, VARIABLE, FILE };
	
	/**
	 * Constructor 
	 * 
	 * @param A model step instance
	 * @param Localized system messages 
	 */
	public StepWindow(Step step, ResourceBundle messages) {
		super(messages.getString("StepWindow.title"));
		
		// Setting attributes
		this.step = step;
		this.messages = messages;
		
		// Configuring the window
		setWidth("600");
		setHeight("400");
		center();
		setModal(true);
		
		// Adds a description to step
		TextField descriptionField = new TextField(messages.getString("StepWindow.descriptionField"));
		descriptionField.setWidth("300");
		addComponent(descriptionField);
		
		// loads bundles from OSGI environment
		loadBundles();
		
		// Creates a dynamic panel to store the selected bundle	
		createBundlePanel();
		
		// Add one combo with test bundles and a dynamic panel to configure the
		// bundles inputs
		addComponent(bundlesCombo);
		addComponent(bundlePanel);
		
		// Add the out put on the window
		TextField outputVariable = new TextField(messages.getString("StepWindow.outputVariable"));
		TextField outputFile = new TextField(messages.getString("StepWindow.outputFile"));	
		addComponent(outputVariable);
		addComponent(outputFile);
		
		// Add a save button to configure the test step object
		Button saveButton = new Button(messages.getString("StepWindow.saveButton"));
		saveButton.addListener(new SaveButtonEvent());
		addComponent(saveButton);
		
		// Makes the window visible
		setVisible(true);
	}
	
	/**
	 * Provate method used to create the bundle panel
	 */
	private void createBundlePanel() {
		bundlePanel = new Panel();
		bundlePanel.setContent(new VerticalLayout());
		bundlePanel.setVisible(false);
	}

	/**
	 * This method retrieves test bundles from OSGI container. Note: 
	 * A test bundle needs to have words like "hawk" and "bundles" in its name
	 */
	private void loadBundles() {
		// Creating the combo to store the system bundles
		bundlesCombo = new ComboBox();
		bundlesCombo.setWidth("300");
		bundlesCombo.setImmediate(true);
		
		// Retrieving the context form OSGI container
		BundleContext context = OsgiContext.getInstance().getContext();
		Bundle[] bundles = context.getBundles();
		
		for (Bundle bundle : bundles) {
			String sn = bundle.getSymbolicName();
			// filtering bundles by name hawk and bundle
			if ((sn.contains("hawk")) && (sn.contains("bundles"))){
				// Add one test bundle inside a combo of bundles
				bundlesCombo.addItem(bundle);
				bundlesCombo.setItemCaption(bundle, bundle.getSymbolicName());
			}
		}
		bundlesCombo.addListener(new ComboEvent());	
	}
	
	/**
	 * Method to create the dynamic tab sheet
	 * 
	 * @param A Graphical user interface of a bundle
	 */
	private void createDynamicTabSheet(BundleGui gui) {
		
		// Remove all components of tab sheet panel
		bundlePanel.removeAllComponents();
		
		// Sets the step window caption
		String bundleName = gui.getName();
		setCaption(bundleName);
		
		// Creates the dynamic tab sheet 
		int count = 1;
		TabSheet tabSheet = new TabSheet();
		Set<String> labels = gui.getLabels();
		if (labels != null){
			for (String label : labels){
				// creates a vertical layout to add combo and text field to each 
				// parameter
				VerticalLayout layout = new VerticalLayout();
				
				// TODO inputCombo in step window are not localized
				// Creates a combo box to configure the data source from input 
				// parameter 
				ComboBox inputCombo = new ComboBox();
				inputCombo.addItem(parameters.VALUE);
				inputCombo.addItem(parameters.VARIABLE);
				inputCombo.addItem(parameters.FILE);
				inputCombo.setNullSelectionAllowed(false);
				
				// Creates a text field to catch the input parameter value 
				TextField inputTextField = new TextField(label);
				String description = gui.getDescription(label);
				inputTextField.setDescription(description);
				
				// add the components in the vertical layout
				layout.addComponent(inputCombo);
				layout.addComponent(inputTextField);
				
				// Creates a new tab for each input parameter
				tabSheet.addTab(layout, messages.getString("StepWindow.tabCaption")
						+ count, null);
				
				count++;
			}
		}
		bundlePanel.addComponent(tabSheet);
		bundlePanel.setVisible(true);
	}
	
	/**
	 * Private class to handle the combo of bundles event. The events are fires
	 * when user changes the combo value 
	 */
	private class ComboEvent implements ValueChangeListener {
		
		/**
		 * Method used to change the combo's value change
		 */
		@Override
		public void valueChange(ValueChangeEvent event) {
			
			// Gets the selected bundle
			Bundle bundle = (Bundle) bundlesCombo.getValue();
			
			if (bundle != null) { 
				// To be reusable, in Hawk one bundle can have only one service
				//TODO change this logic ([0]) if a bundle can have more than one service 
				// gets the bundle reference
				ServiceReference reference = bundle.getRegisteredServices()[0];
				BundleContext context = OsgiContext.getInstance().getContext();
				// Gets the bundle service through reference
				TestService testBundle = (TestService) context.getService(reference);

				try {
					// Retrieve the bundle interface in XML
					String xml = testBundle.getBundleInterface();
					
					if (xml != null){
						// Creates the bundle interface from XML file
						BundleGui gui = new BundleGui();
						gui.generate(xml);
						
						// Creates the dynamic tab sheet 
						createDynamicTabSheet(gui);
					}
				} 
				catch (Exception e) {
					showNotification(messages.getString("StepWindow.warning"), 
							Notification.TYPE_WARNING_MESSAGE);
				}
			}
			else{
				// put the window in the original state
				setCaption(messages.getString("StepWindow.title"));
				bundlePanel.removeAllComponents();
				bundlePanel.setVisible(false);
			}
		}		
	} 
	
	/**
	 * Class to handle the save button event
	 */
	private class SaveButtonEvent implements ClickListener {

		public void buttonClick(ClickEvent event) {
			
		}
	}
}